﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Reflection;
using System.Text;
using System.Xml;

namespace GrainManage.Server.Util
{

    public sealed class WebUtil
    {
        public static ResultModel GetResultFromJsonByPost<ResultModel>(string resource, object inputParams) where ResultModel : class
        {
            var data = RequestByPost(resource, inputParams);
            return JsonToResult<ResultModel>(data);
        }

        public static ResultModel GetResultFromJsonByGet<ResultModel>(string resource, string parameters, string propertyName = "") where ResultModel : class
        {
            //parameters like:name=john&age=20
            var data = RequestByGet(resource, parameters);
            return JsonToResult<ResultModel>(data, propertyName);
        }

        public static List<ResultModel> GetResultFromXmlByGet<ResultModel>(string resource) where ResultModel : class,new()
        {
            var data = RequestByGet(resource, string.Empty);
            return XmlToResult<ResultModel>(data);
        }

        public static byte[] DownloadFile(string resource)
        {
            byte[] result = null;
            var request = WebRequest.Create(resource) as HttpWebRequest;
            request.Method = "GET";   // Set type to GET
            using (var response = request.GetResponse() as HttpWebResponse)
            {
                using (var stream = response.GetResponseStream())
                {
                    using (var reader = new BinaryReader(stream))
                    {
                        result = reader.ReadBytes(Convert.ToInt32(response.ContentLength));
                    }
                }
            }

            return result;
        }

        #region Process Request

        private static string RequestByPost(string resource, object inputParams)
        {
            var result = string.Empty;
            var strInput = JsonSerialize(inputParams);
            var byteData = UTF8Encoding.UTF8.GetBytes(strInput);// Create a byte array of the data we want to send

            var request = WebRequest.Create(resource) as HttpWebRequest;
            request.Method = "POST"; // Set type to POST
            request.ContentType = "application/json";
            //request.ContentType = "text/xml";
            request.ContentLength = byteData.Length;  // Set the content length in the request headers

            using (var postStream = request.GetRequestStream())
            {
                postStream.Write(byteData, 0, byteData.Length);  // Write data
            }

            using (var response = request.GetResponse() as HttpWebResponse)  // Get response
            {
                using (var stream = response.GetResponseStream())  // Get the response stream
                {
                    using (var reader = new StreamReader(stream))
                    {
                        result = reader.ReadToEnd();
                    }
                }
            }

            return result;
        }

        private static string RequestByGet(string resource, string parameters)
        {
            var result = string.Empty;

            var url = string.IsNullOrEmpty(parameters) ? resource : resource + "?" + parameters;
            var request = WebRequest.Create(url) as HttpWebRequest;
            request.Method = "GET";   // Set type to GET
            request.ContentType = "text/html; charset=utf-8";
            using (var response = request.GetResponse() as HttpWebResponse)
            {
                using (var stream = response.GetResponseStream())
                {
                    if (response.ContentEncoding == "gzip")
                    {
                        using (var gzipStream = new GZipStream(stream, CompressionMode.Decompress))
                        {
                            using (var reader = new StreamReader(gzipStream, Encoding.UTF8))
                            {
                                result = reader.ReadToEnd();
                            }
                        }
                    }
                    else
                    {
                        using (var reader = new StreamReader(stream, Encoding.UTF8))
                        {
                            result = reader.ReadToEnd();
                        }
                    }
                }
            }

            return result;
        }

        private static bool HasWeatherInfo(string requestData)
        {
            bool isRight = true;
            if (string.IsNullOrWhiteSpace(requestData) || requestData.StartsWith(AppConfig.GetValue("InvalidWeatherFlag")))
            {
                isRight = false;
            }
            return isRight;
        }

        #endregion

        #region Process Json

        private static ResultModel JsonToResult<ResultModel>(string jsonData, string propertyName = "") where ResultModel : class
        {
            ResultModel result = default(ResultModel);
            if (HasWeatherInfo(jsonData))
            {
                if (typeof(ResultModel) == typeof(string))
                {
                    result = jsonData as ResultModel;
                }
                else
                {
                    if (string.IsNullOrEmpty(propertyName))
                    {
                        result = JsonDeserialize<ResultModel>(jsonData);
                    }
                    else
                    {
                        JObject jo = JObject.Parse(jsonData);
                        JToken jt = jo[propertyName];
                        if (jt != null)
                        {
                            result = jt.ToObject<ResultModel>();
                        }
                    }
                }
            }
            return result;
        }

        private static string JsonSerialize(object obj)
        {
            return JsonConvert.SerializeObject(obj);
        }

        private static TModel JsonDeserialize<TModel>(string json)
        {
            var settings = new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error };
            return JsonConvert.DeserializeObject<TModel>(json, settings);
        }

        #endregion

        #region Process Xml

        private static List<TModel> XmlToResult<TModel>(string xml) where TModel : class,new()
        {
            List<TModel> result = default(List<TModel>);
            if (HasWeatherInfo(xml))
            {
                result = new List<TModel>();
                Type entityType = typeof(TModel);
                var properties = entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                using (var strReader = new System.IO.StringReader(xml))
                {
                    using (var xmlReader = new XmlTextReader(strReader))
                    {
                        while (xmlReader.Read())
                        {
                            if (xmlReader.Depth == 1 && xmlReader.NodeType == XmlNodeType.Element)
                            {
                                var entity = new TModel();
                                foreach (var property in properties)
                                {
                                    var propValue = xmlReader.GetAttribute(property.Name);
                                    property.SetValue(entity, propValue, null);
                                }
                                result.Add(entity);
                            }
                        }
                    }
                }
            }
            return result;
        }

        #endregion
    }
}